package http

import (
	"context"
	"gitee.com/sdynasty/yogurt/transport"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/mux"
)

type GinAdapter interface {
	GinHandler() gin.HandlerFunc
	FromGinContext(*gin.Context) Context
	Payload(c *gin.Context, out any)
}

type adapter struct {
	srv *Server
}

func newAdapter(s *Server) *adapter {
	return &adapter{srv: s}
}

func (a *adapter) GinHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		var (
			ctx    context.Context
			cancel context.CancelFunc
			req    = c.Request
		)
		if a.srv.timeout > 0 {
			ctx, cancel = context.WithTimeout(req.Context(), a.srv.timeout)
		} else {
			ctx, cancel = context.WithCancel(req.Context())
		}
		defer cancel()

		pathTemplate := req.URL.Path
		if route := mux.CurrentRoute(req); route != nil {
			pathTemplate, _ = route.GetPathTemplate()
		}
		tr := &Transport{
			operation:    pathTemplate,
			reqHeader:    headerCarrier(req.Header),
			replyHeader:  headerCarrier(c.Writer.Header()),
			request:      req,
			pathTemplate: pathTemplate,
		}
		if a.srv.endpoint != nil {
			tr.endpoint = a.srv.endpoint.String()
		}
		tr.request = req.WithContext(transport.NewServerContext(ctx, tr))
		c.Request = tr.request

		c.Next()

		if errs := c.Errors; len(errs) > 0 {
			a.srv.ene(c.Writer, c.Request, errs[0])
			return
		}
		if payload, ok := c.Get(PayloadKey); ok {
			a.srv.enc(c.Writer, c.Request, payload)
			return
		}
	}
}

func (a *adapter) FromGinContext(c *gin.Context) Context {
	w := &wrapper{
		srv: a.srv,
	}
	w.Reset(c)
	return w
}

func (a *adapter) Payload(c *gin.Context, out any) {
	c.Set(PayloadKey, out)
}
